/**
 * @fileOverview The "panel" plugin.
 */
(function() {
   VED.plugins.add( 'panel', {
      beforeInit: function( editor ) {
         editor.ui.addHandler( VED.UI_PANEL, VED.ui.panel.handler );
      }
   });

   VED.UI_PANEL = 'panel';

   VED.ui.panel = new Class({
      initialize: function( document, definition ) {
         // Copy all definition properties to this object.
         if ( definition )
            VED.tools.extend( this, definition );

         // Set defaults.
         VED.tools.extend( this, {
            className: '',
            css: []
         });

         this.id = VED.tools.getNextId();
         this.document = document;
         this.isFramed = this.forceIFrame || this.css.length;

         this._ = {
            blocks: {}
         };
      }
   });

   VED.ui.panel.handler = {
      create: function( definition ) {
         return new VED.ui.panel( definition );
      }
   };

   var panelTpl = VED.addTemplate( 'panel', '<div lang="{langCode}" id="{id}" dir={dir}' +
      ' class="ved ved_reset_all {editorId} ved_panel ved_panel {cls} ved_{dir}"' +
      ' style="z-index:{z-index}" role="presentation">' +
      '{frame}' +
      '</div>' );

   var frameTpl = VED.addTemplate( 'panel-frame', '<iframe id="{id}" class="ved_panel_frame" role="presentation" frameborder="0" src="{src}"></iframe>' );

   var frameDocTpl = VED.addTemplate( 'panel-frame-inner', '<!DOCTYPE html>' +
      '<html class="ved_panel_container {env}" dir="{dir}" lang="{langCode}">' +
         '<head>{css}</head>' +
         '<body class="ved_{dir}"' +
            ' style="margin:0;padding:0" onload="{onload}"></body>' +
      '<\/html>' );

   /** @class VED.ui.panel */
   VED.ui.panel.implement({

      render: function( editor, output ) {
         this.getHolderElement = function() {
            var holder = this._.holder;

            if ( !holder ) {
               if ( this.isFramed ) {
                  var iframe = this.document.getById( this.id + '_frame' ),
                     parentDiv = iframe.getParent(),
                     doc = iframe.getFrameDocument();

                  // Make it scrollable on iOS. (#8308)
                  VED.env.iOS && parentDiv.setStyles({
                     'overflow': 'scroll',
                     '-webkit-overflow-scrolling': 'touch'
                  });

                  var onLoad = VED.tools.addFunction( VED.tools.bind( function( ev ) {
                     this.isLoaded = true;
                     if ( this.onLoad )
                        this.onLoad();
                  }, this ) );

                  doc.write( frameDocTpl.output( VED.tools.extend({
                     css: VED.tools.buildStyleHtml( this.css ),
                     onload: 'window.parent.VED.tools.callFunction(' + onLoad + ');'
                  }, data ) ) );

                  var win = doc.getWindow();

                  // Register the VED global.
                  win.$.VED = VED;

                  // Arrow keys for scrolling is only preventable with 'keypress' event in Opera (#4534).
                  doc.on( 'key' + ( VED.env.opera ? 'press' : 'down' ), function( evt ) {
                     var keystroke = evt.data.getKeystroke(),
                        dir = this.document.getById( this.id ).getAttribute( 'dir' );

                     // Delegate key processing to block.
                     if ( this._.onKeyDown && this._.onKeyDown( keystroke ) === false ) {
                        evt.data.preventDefault();
                        return;
                     }

                     // ESC/ARROW-LEFT(ltr) OR ARROW-RIGHT(rtl)
                     if ( keystroke == 27 || keystroke == ( dir == 'rtl' ? 39 : 37 ) ) {
                        if ( this.onEscape && this.onEscape( keystroke ) === false )
                           evt.data.preventDefault();
                     }
                  }, this );

                  holder = doc.getBody();
                  holder.unselectable();
                  VED.env.air && VED.tools.callFunction( onLoad );
               } else
                  holder = this.document.getById( this.id );

               this._.holder = holder;
            }

            return holder;
         };

         var data = {
            editorId: editor.id,
            id: this.id,
            langCode: editor.langCode,
            dir: editor.lang.dir,
            cls: this.className,
            frame: '',
            env: VED.env.cssClass,
            'z-index': editor.config.baseFloatZIndex + 1
         };

         // With IE, the custom domain has to be taken care at first,
         // for other browers, the 'src' attribute should be left empty to
         // trigger iframe's 'load' event.
         var src =
            VED.env.air ? 'javascript:void(0)' :
            VED.env.ie ? 'javascript:void(function(){' + encodeURIComponent(
               'document.open();' +
               // In IE, the document domain must be set any time we call document.open().
               '(' + VED.tools.fixDomain + ')();' +
               'document.close();'
            ) + '}())' :
            '';

         if ( this.isFramed ) {
            data.frame = frameTpl.output({
               id: this.id + '_frame',
               src: src
            });
         }

         var html = panelTpl.output( data );

         if ( output )
            output.push( html );

         return html;
      },

      addBlock: function( name, block ) {
         block = this._.blocks[ name ] = block instanceof VED.ui.panel.block ? block : new VED.ui.panel.block( this.getHolderElement(), block );

         if ( !this._.currentBlock )
            this.showBlock( name );

         return block;
      },

      getBlock: function( name ) {
         return this._.blocks[ name ];
      },

      showBlock: function( name ) {
         var blocks = this._.blocks,
            block = blocks[ name ],
            current = this._.currentBlock;

         // ARIA role works better in IE on the body element, while on the iframe
         // for FF. (#8864)
         var holder = !this.forceIFrame || VED.env.ie ? this._.holder : this.document.getById( this.id + '_frame' );

         if ( current ) {
            // Clean up the current block's effects on holder.
            holder.removeAttributes( current.attributes );
            current.hide();
         }

         this._.currentBlock = block;

         holder.setAttributes( block.attributes );
         VED.fire( 'ariaWidget', holder );

         // Reset the focus index, so it will always go into the first one.
         block._.focusIndex = -1;

         this._.onKeyDown = block.onKeyDown && VED.tools.bind( block.onKeyDown, block );

         block.show();

         return block;
      },

      destroy: function() {
         this.element && this.element.remove();
      }
   });

   /**
    * @class
    */
   VED.ui.panel.block = new Class({

      initialize: function( blockHolder, blockDefinition ) {
         this.element = blockHolder.append( blockHolder.getDocument().createElement( 'div', {
            attributes: {
               'tabIndex': -1,
               'class': 'ved_panel_block',
               'role': 'presentation',
               'tabindex': 0
            },
            styles: {
               display: 'none'
            }
         }));

         // Copy all definition properties to this object.
         if ( blockDefinition )
            VED.tools.extend( this, blockDefinition );

         // Set the a11y attributes of this element ...
         this.element.setAttributes( {
            'aria-label': this.attributes[ 'aria-label' ],
            'title': this.attributes.title || this.attributes[ 'aria-label' ]
         } );

         // ...  and remove them from being set in the panel main element.
         delete this.attributes[ 'aria-label' ];
         delete this.attributes.title;

         this.keys = {};

         this._.focusIndex = -1;

         // Disable context menu for panels.
         this.element.disableContextMenu();
      },

      _: {
         /**
          * Mark the item specified by the index as current activated.
          */
         markItem: function( index ) {
            if ( index == -1 )
               return;
            var links = this.element.getElementsByTag( 'a' );
            var item = links.getItem( this._.focusIndex = index );

            // Safari need focus on the iframe window first(#3389), but we need
            // lock the blur to avoid hiding the panel.
            if ( VED.env.webkit || VED.env.opera )
               item.getDocument().getWindow().focus();
            item.focus();

            this.onMark && this.onMark( item );
         }
      },

      show: function() {
         this.element.setStyle( 'display', '' );
      },

      hide: function() {
         if ( !this.onHide || this.onHide.call( this ) !== true )
            this.element.setStyle( 'display', 'none' );
      },

      onKeyDown: function( keystroke ) {
         var keyAction = this.keys[ keystroke ];
         switch ( keyAction ) {
            // Move forward.
            case 'next':
               var index = this._.focusIndex,
                  links = this.element.getElementsByTag( 'a' ),
                  link;

               while ( ( link = links.getItem( ++index ) ) ) {
                  // Move the focus only if the element is marked with
                  // the _ved_focus and it it's visible (check if it has
                  // width).
                  if ( link.getAttribute( '_ved_focus' ) && link.$.offsetWidth ) {
                     this._.focusIndex = index;
                     link.focus();
                     break;
                  }
               }
               return false;

               // Move backward.
            case 'prev':
               index = this._.focusIndex;
               links = this.element.getElementsByTag( 'a' );

               while ( index > 0 && ( link = links.getItem( --index ) ) ) {
                  // Move the focus only if the element is marked with
                  // the _ved_focus and it it's visible (check if it has
                  // width).
                  if ( link.getAttribute( '_ved_focus' ) && link.$.offsetWidth ) {
                     this._.focusIndex = index;
                     link.focus();
                     break;
                  }
               }
               return false;

            case 'click':
            case 'mouseup':
               index = this._.focusIndex;
               link = index >= 0 && this.element.getElementsByTag( 'a' ).getItem( index );

               if ( link )
                  link.$[ keyAction ] ? link.$[ keyAction ]() : link.$[ 'on' + keyAction ]();

               return false;
         }

         return true;
      }
   });

})();






